package jumpingnotes.dao.hibernate;

import java.util.ArrayList;
import java.util.List;

import jumpingnotes.dao.BookDao;
import jumpingnotes.model.entity.Book;
import jumpingnotes.model.entity.BookTagRelation;
import net.jf.lucene.analysis.mmseg.MMSegAnalyzer;

import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.Search;
import org.springframework.orm.hibernate3.HibernateCallback;

public class BookHibernateDao extends GenericHibernateDao<Book> implements BookDao
{
	public BookHibernateDao()
	{
		super(Book.class);
	}

	@SuppressWarnings("unchecked")
	public List<Book> findBookByBookTag(final String bookTag, final int firstResult, final int maxResults)
	{
		return (List<Book>) getHibernateTemplate().execute(new HibernateCallback()
		{
			public Object doInHibernate(Session session) throws HibernateException
			{
				Criteria criteria = session.createCriteria(BookTagRelation.class);
				criteria.createAlias("bookTag", "bookTag");
				criteria.add(Restrictions.eq("bookTag.tagName", bookTag));
				criteria.setFetchMode("book", FetchMode.JOIN);

				if (firstResult >= 0)
					criteria.setFirstResult(firstResult);
				if (maxResults > 0)
					criteria.setMaxResults(maxResults);

				List<BookTagRelation> relationList = criteria.list();

				List<Book> bookList = new ArrayList<Book>();
				for (BookTagRelation relation : relationList)
				{
					Book book = relation.getBook();
					bookList.add(book);
				}
				return bookList;
			}
		});
	}

	@SuppressWarnings("unchecked")
	public List<Book> findFavoriteBookByMemberId(final int memberId)
	{
		return (List<Book>) getHibernateTemplate().execute(new HibernateCallback()
		{
			public Object doInHibernate(Session session) throws HibernateException
			{
				Query query = session
						.createQuery("select distinct b from Book b join b.bookFavorites bf where bf.member.memberId=:memberId");
				query.setInteger("memberId", memberId);
				return query.list();
			}
		});
	}

	@SuppressWarnings("unchecked")
	public List<Book> findBookLatest(final int firstResult, final int maxResults)
	{
		return (List<Book>) getHibernateTemplate().execute(new HibernateCallback()
		{
			public Object doInHibernate(Session session) throws HibernateException
			{
				Query query = session.createQuery("select distinct b from Book b order by b.createTime desc");

				if (firstResult >= 0)
					query.setFirstResult(firstResult);
				if (maxResults > 0)
					query.setMaxResults(maxResults);

				return query.list();
			}
		});
	}

	@SuppressWarnings("unchecked")
	public List<Book> findBookPlayTop(final int firstResult, final int maxResults)
	{
		return (List<Book>) getHibernateTemplate().execute(new HibernateCallback()
		{
			public Object doInHibernate(Session session) throws HibernateException
			{
				Query query = session.createQuery("select b from Book b join b.recordAlbums ra group by b order by sum(ra.playCount) desc");

				if (firstResult >= 0)
					query.setFirstResult(firstResult);
				if (maxResults > 0)
					query.setMaxResults(maxResults);

				return query.list();
			}
		});
	}

	@SuppressWarnings("unchecked")
	public List<Book> findBookRateTop(final int firstResult, final int maxResults)
	{
		return (List<Book>) getHibernateTemplate().execute(new HibernateCallback()
		{
			public Object doInHibernate(Session session) throws HibernateException
			{
				Query query = session.createQuery("select b from Book b join b.recordAlbums ra group by b order by sum(ra.ratingTotal)/sum(ra.ratingCount) desc");

				if (firstResult >= 0)
					query.setFirstResult(firstResult);
				if (maxResults > 0)
					query.setMaxResults(maxResults);

				return query.list();
			}
		});
	}

	@SuppressWarnings("unchecked")
	public List<Book> findBookRecommend(final int firstResult, final int maxResults)
	{
		return (List<Book>) getHibernateTemplate().execute(new HibernateCallback()
		{
			public Object doInHibernate(Session session) throws HibernateException
			{
				// TODO algorithm for recommended books
				Query query = session.createQuery("from Book b");

				if (firstResult >= 0)
					query.setFirstResult(firstResult);
				if (maxResults > 0)
					query.setMaxResults(maxResults);

				return query.list();
			}
		});
	}

	@SuppressWarnings("unchecked")
	public void indexBook()
	{
		Session session = getSession();
		FullTextSession fullTextSession = Search.createFullTextSession(session);

		List<Book> bookList = session.createCriteria(Book.class).list();
		for (Book book : bookList)
		{
			fullTextSession.index(book);
		}
	}

	@SuppressWarnings("unchecked")
	public List<Book> searchBook(String keyword, int firstResult, int maxResults)
	{
		Session session = getSession();
		FullTextSession fullTextSession = Search.createFullTextSession(session);

		try
		{
			MultiFieldQueryParser parser = new MultiFieldQueryParser(new String[] {
					"name", "subTitle", "abstract_", "author", "authorIntro"
			}, new MMSegAnalyzer());
			org.apache.lucene.search.Query query = parser.parse(keyword);
			Query hibQuery = fullTextSession.createFullTextQuery(query, Book.class);

			if (firstResult >= 0)
				hibQuery.setFirstResult(firstResult);
			if (maxResults > 0)
				hibQuery.setMaxResults(maxResults);

			List<Book> result = hibQuery.list();
			return result;
		}
		catch (ParseException e)
		{
			e.printStackTrace();
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	public List<Book> searchBookByName(String keyword, int firstResult, int maxResults)
	{
		Session session = getSession();
		FullTextSession fullTextSession = Search.createFullTextSession(session);

		try
		{
			MultiFieldQueryParser parser = new MultiFieldQueryParser(new String[] {
					"name", "subTitle"
			}, new MMSegAnalyzer());
			org.apache.lucene.search.Query query = parser.parse(keyword);
			Query hibQuery = fullTextSession.createFullTextQuery(query, Book.class);

			if (firstResult >= 0)
				hibQuery.setFirstResult(firstResult);
			if (maxResults > 0)
				hibQuery.setMaxResults(maxResults);

			List<Book> result = hibQuery.list();
			return result;
		}
		catch (ParseException e)
		{
			e.printStackTrace();
			return null;
		}
	}

	@SuppressWarnings("unchecked")
	public List<Book> searchBookByAuthor(String keyword, int firstResult, int maxResults)
	{
		Session session = getSession();
		FullTextSession fullTextSession = Search.createFullTextSession(session);

		try
		{
			MultiFieldQueryParser parser = new MultiFieldQueryParser(new String[] {
				"author"
			}, new MMSegAnalyzer());
			org.apache.lucene.search.Query query = parser.parse(keyword);
			Query hibQuery = fullTextSession.createFullTextQuery(query, Book.class);

			if (firstResult >= 0)
				hibQuery.setFirstResult(firstResult);
			if (maxResults > 0)
				hibQuery.setMaxResults(maxResults);

			List<Book> result = hibQuery.list();
			return result;
		}
		catch (ParseException e)
		{
			e.printStackTrace();
			return null;
		}
	}
}
